package com.company.exp2.event;

import com.company.exp2.station.Station;
import com.company.exp2.typeEnum.EventType;

/**
 * @author dyy
 *
 * Event 是所有搭载在时间线上的实体
 * 他并不是整个信道中实际存在的实体，而是对于每一个改变模型现有状态的事件的抽象
 * 他应该只携带一些回调函数，和必要的基本信息
 *
 * 现在应该实现的基本事件有：
 *     模型启动事件
 *     帧产生事件
 *     帧开始传输事件
 *     帧结束传输时间
 *     帧传输超时事件
 *     信道可传输事件 ：”再上一个传输时间结束后的下一个时间槽触发的事件，此时所有想要传输帧的站点开始竞争“
 *     信道禁止传输事件
 *
 */
public abstract class Event {

    protected final long timestamp;             // 事件发生的时间点
    protected final Station associatedStation;  // 事件相关的站点
    private boolean isValid;                    // 当前事件是否有效

    /**
     * @param timestamp 事件发生的时间戳
     */
    public Event(long timestamp, Station associatedStation) {
        this.timestamp = timestamp;
        this.associatedStation = associatedStation;
        this.isValid = true;
    }

    /**
     * 事件触发时具体地执行操作
     */
    public abstract void occur();

    /**
     * 获取Event的类型
     * 用于DEBUG中了解当前Event类型
     */
    public abstract EventType getEventType();

    /**
     * 获取当前事件的发生时间戳
     * @return long 时间戳
     */
    public long getTimestamp() {
        return timestamp;
    }

    /**
     * 获取当前事件相关的站点
     * @return Station 相关站点
     */
    public Station getAssociatedStation() {
        return associatedStation;
    }

    /**
     * 返回当前事件是否有效
     * 有时候因为某种原因当前时间失效，需要在执行事件时确认
     * 事件默认是有效的
     */
    public boolean isValid() {
       return isValid;
    }

    /**
     * 取消事件
     * 目前取消事件的主要原因是站点由于冻结自身的回退倒计时，导致之前声明的传输事件发生时间点失效
     * 为了简化模型，应当取消先前声明的发送事件并重新在新的正确的时间点声明一个事件
     */
    public void cancel() {
        assert isValid : "试图去取消一个已经取消的事件";
        isValid = false;
    }
}
